// 测试弹窗入口（可随时移除）
import { showLinkDrawTestDialog } from './testLinkDrawStrategy.js';
window.showLinkDrawTestDialog = showLinkDrawTestDialog;

// 页面加载后自动渲染网络图
if (typeof updateGraph === 'function') {
    updateGraph();
}
// import { DatabaseAPI } from "./dbAPI.js"; // Removed: direct dbAPI usage is forbidden; use only networkAPI.js
import { NetworkAPI } from './networkAPI.js';

import { ensureTagifySyncLoaded } from './globalMgr.js';
ensureTagifySyncLoaded();

// 屏蔽 Firefox InstallTrigger 警告，防止 Tagify 检测到
try { window.InstallTrigger = undefined; } catch(e) {}
// 自动引入 pinyin-pro（本地 UMD 版，window.pinyinPro 全局可用）
if (!window.pinyinPro) {
    const script = document.createElement('script');
    script.src = '/static/visualizer/js/pinyin-pro.js';
    script.type = 'text/javascript';
    document.head.appendChild(script);
}

import { nodes, links, getPinyinFirstLetters, enableResize, drawPopupNodeCurve, redrawLineOfPopupAndNode } from "./globalMgr.js";

// 创建SVG元素
import { svg, width, height, simulation, node, updateGraph } from "./graphicsAPI.js";

// 关键：每次节点渲染后都重新绑定drop事件
if (window.__bindRemoveNodePickDrop) window.__bindRemoveNodePickDrop();

// 节点hover动画
node.on('mouseenter', function(event, d) {
    d3.select(this).select('circle')
        .transition()
        .duration(500)
        .attr('r', d.radius + 10);
})
    .on('mouseleave', function(event, d) {
        d3.select(this).select('circle')
            .transition()
            .duration(500)
            .attr('r', d.radius);
    });

// 添加键盘事件监听
document.addEventListener('keydown', (event) => {
    const helpPanel = d3.select('.help-panel');
    const searchBox = d3.select('.search-box');
    if (event.key === '?') {
        helpPanel.style('display', 'block');
        searchBox.style('display', 'none');
    } 
    else if (event.key === '/') {
        // 只有当焦点不在输入框时才触发搜索
        const activeElement = document.activeElement;
        if (activeElement.tagName !== 'INPUT' && activeElement.tagName !== 'TEXTAREA') {
            event.preventDefault();
            searchBox.style('display', 'block');
            helpPanel.style('display', 'none');
            searchBox.select('input').node().focus();
        }
    }
    else if (event.key === 'Escape') {
        helpPanel.style('display', 'none');
        searchBox.style('display', 'none');
        // 重新获取最新的 node 选择器
        d3.selectAll('.node-group').classed('highlight', false);
        searchBox.select('input').property('value', '');
    }
});



// 保证每次节点渲染后都绑定点击事件
function bindNodeDetailPopup() {
    node.on('click', function(event, d) {
        updateNodeDetails(d);
    });
}

// 挂载到 window，供 graphicsAPI.js 动态调用
window.bindNodeDetailPopup = bindNodeDetailPopup;
// 首次绑定
bindNodeDetailPopup();
// 每次 updateGraph 后重新绑定
const oldUpdateGraph = updateGraph;
window.updateGraph = function(...args) {
    const result = oldUpdateGraph.apply(this, args);
    bindNodeDetailPopup();
    return result;
};

// 从globalMgr.js导入共享的nodePopupRegistry
import { nodePopupRegistry } from './globalMgr.js';

function updateNodeDetails(nodeData) {
    // 如果该节点已有弹窗，则直接返回
    if (nodePopupRegistry.has(nodeData.id)) {
        return;
    }

    const connectionCount = links.reduce((count, link) =>
        count + (link.source === nodeData.id || link.target === nodeData.id ? 1 : 0), 0);
    const connectedNodes = links
        .filter(link => link.source === nodeData.id || link.target === nodeData.id)
        .map(link => {
            const otherId = link.source === nodeData.id ? link.target : link.source;
            const otherNode = nodes.find(n => n.id === otherId);
            return otherNode ? (otherNode.name || otherNode.id) : otherId;
        });

    // 弹窗初始参数
    let dragOffset = { x: 0, y: 0 };
    // 获取SVG节点在页面上的位置
    const svgNode = document.querySelector('svg');
    const svgRect = svgNode.getBoundingClientRect();
    // 获取节点坐标
    const node = nodeData;
    const nodeX = node.x, nodeY = node.y;
    // 计算弹窗初始位置（节点右上方）
    let popupLeft = svgRect.left + nodeX + 60;
    let popupTop = svgRect.top + nodeY + (node.radius || 0) + 40 - 20;
    // 创建弹窗div
    const popupDiv = document.createElement('div');
    popupDiv.className = 'node-details-popup node-details-popup-div draggable-popup';
    popupDiv.style.position = 'fixed';
    popupDiv.style.left = popupLeft + 'px';
    popupDiv.style.top = popupTop + 'px';
    popupDiv.style.minWidth = '360px';
    popupDiv.style.minHeight = '400px';
    popupDiv.style.maxWidth = 'none';
    popupDiv.style.maxHeight = 'none';
    popupDiv.style.zIndex = 9999;
    popupDiv.style.display = 'flex';
    popupDiv.style.flexDirection = 'column';
    popupDiv.style.resize = 'both';
    popupDiv.style.overflow = 'visible';
    popupDiv.innerHTML = `
        <div class="node-details-header" style="position:sticky;top:0;left:0;width:100%;height:40px;background:#f5f5f5;border-radius:8px 8px 0 0;display:flex;align-items:center;justify-content:space-between;margin:0;z-index:10000;transition:all 0.2s;">
            <div class="node-details-dragbar" style="width:100%;height:100%;cursor:move;user-select:none;display:flex;align-items:center;color:#666;font-size:13px;padding:0 10px;">⇕ 拖动移动</div>
            <div class="node-details-buttons" style="display:flex;gap:8px;">
                <button class="node-details-maximize-btn" style="width:32px;height:32px;background:rgba(255,255,255,0.8);border:none;border-radius:16px;box-shadow:0 2px 6px rgba(0,0,0,0.12);cursor:pointer;display:flex;align-items:center;justify-content:center;margin-right:8px;transition:background-color 0.2s;position:relative;top:-1px;">
                    <span class="node-details-maximize-icon" style="font-size:18px;line-height:1;">□</span>
                </button>
                <button class="node-details-close-btn" style="width:32px;height:32px;background:rgba(255,255,255,0.8);border:none;border-radius:16px;box-shadow:0 2px 6px rgba(0,0,0,0.12);cursor:pointer;display:flex;align-items:center;justify-content:center;margin-right:8px;transition:background-color 0.2s;position:relative;top:-1px;">
                    <span class="node-details-close-icon" style="font-size:22px;line-height:1;">×</span>
                </button>
            </div>
        </div>
        <div class="node-details-container" style="position:relative;height:calc(100% - 40px);padding:0 10px;">
            <h4 class="node-details-title">${nodeData.name || 'Unnamed Node'}</h4>
            <p class="node-details-row"><strong>ID:</strong> ${nodeData.id}</p>
            <p class="node-details-row"><strong>Description:</strong> 
                <div id="node-desc-container">
                    <span id="node-desc-content" style="display:inline-block;vertical-align:top;"></span>
                    <div id="node-desc-editor" style="display:none;"></div>
                </div>
                <select id="node-desc-type-select" class="desc-type-select" style="margin-left:8px;">
                    <option value="plain">纯文本</option>
                    <option value="markdown">Markdown</option>
                    <option value="html">HTML</option>
                </select>
                <button id="edit-desc-btn" class="edit-desc-btn" style="margin-left:8px;">编辑</button>
                <button id="save-desc-btn" class="save-desc-btn" style="display:none;margin-left:8px;">保存</button>
                <button id="cancel-edit-btn" class="cancel-edit-btn" style="display:none;margin-left:8px;">取消</button>
            </p>
            <p class="node-details-row"><strong>Connections:</strong> ${connectionCount}</p>
            ${connectionCount > 0 ? `
                <div class="node-connections-list">
                    <p style="margin: 0 0 5px 0; font-weight: bold;">Connected to:</p>
                    <ul style="margin: 0; padding-left: 20px;">
                        ${connectedNodes.map(name => `<li style=\"margin-bottom: 3px;\">${name}</li>`).join('')}
                    </ul>
                </div>
            ` : ''}
        </div>
    `;
    document.body.appendChild(popupDiv);
    // 渲染 description 字段，支持 desc_type
    setTimeout(() => {
        const descType = nodeData.desc_type || 'plain';
        const descEl = popupDiv.querySelector('#node-desc-content');
        const descEditor = popupDiv.querySelector('#node-desc-editor');
        const descTypeSelect = popupDiv.querySelector('#node-desc-type-select');
        const editBtn = popupDiv.querySelector('#edit-desc-btn');
        const saveBtn = popupDiv.querySelector('#save-desc-btn');
        const cancelBtn = popupDiv.querySelector('#cancel-edit-btn');
        let originalDesc = nodeData.description || ''; // 保存原始描述
        
        // 确保marked.js加载
        if (!window.marked && descType === 'markdown') {
            const script = document.createElement('script');
            script.src = '/static/visualizer/js/marked.min.js';
            document.head.appendChild(script);
        }
        
        // 设置当前desc_type
        descTypeSelect.value = descType;
        
        // 编辑按钮点击事件
        editBtn.addEventListener('click', function() {
            // 显示编辑器和保存按钮
            descEl.style.display = 'none';
            descEditor.style.display = 'block';
            editBtn.style.display = 'none';
            saveBtn.style.display = 'inline-block';
            cancelBtn.style.display = 'inline-block';
            
            // 根据类型初始化编辑器
            const desc = nodeData.description || '';
            if (descType === 'markdown') {
                // 初始化markdown编辑器
                descEditor.innerHTML = `<textarea style="width:100%;height:100px">${desc}</textarea>`;
            } else if (descType === 'html') {
                // 初始化html编辑器
                descEditor.innerHTML = `<textarea style="width:100%;height:100px">${desc}</textarea>`;
            } else {
                // 纯文本编辑器
                descEditor.innerHTML = `<textarea style="width:100%;height:60px">${desc}</textarea>`;
            }
        });

        // 保存按钮点击事件
        saveBtn.addEventListener('click', async function() {
            // 获取编辑内容
            const editor = descEditor.querySelector('textarea');
            const newDesc = editor ? editor.value : '';
            
            // 更新本地数据
            nodeData.description = newDesc;
            const newDescType = descTypeSelect.value;
            
            // 调用API保存
            const success = await NetworkAPI.updateNodeDescription(
                nodeData.id,
                newDesc,
                newDescType
            );
            
            if (success) {
                // 更新本地数据
                nodeData.desc_type = newDescType;
                // 切换回预览模式
                descEl.style.display = 'inline-block';
                descEditor.style.display = 'none';
                editBtn.style.display = 'inline-block';
                saveBtn.style.display = 'none';
                cancelBtn.style.display = 'none';
                // 直接更新预览区内容
                const desc = nodeData.description || '';
                const descType = nodeData.desc_type || 'plain';
                const currentDescEl = popupDiv.querySelector('#node-desc-content');
                
                if (!currentDescEl) {
                    console.error('Description element not found');
                    return;
                }
                
                if (!desc) {
                    currentDescEl.textContent = '点击"编辑"添加描述';
                    currentDescEl.style.color = '#666';
                    currentDescEl.style.fontStyle = 'italic';
                } else if (descType === 'markdown') {
                    if (window.marked) {
                        try {
                            currentDescEl.innerHTML = marked.parse(desc);
                            currentDescEl.style.padding = '6px 10px';
                            currentDescEl.style.background = '#f8f8fa';
                            currentDescEl.style.borderRadius = '6px';
                        } catch (e) {
                            console.error('Markdown渲染失败:', e);
                            currentDescEl.textContent = desc + ' (渲染错误)';
                        }
                    } else {
                        currentDescEl.textContent = desc + ' (请加载marked.js)';
                    }
                } else if (descType === 'html') {
                    currentDescEl.innerHTML = desc;
                    currentDescEl.style.padding = '6px 10px';
                    currentDescEl.style.background = '#f8f8fa';
                    currentDescEl.style.borderRadius = '6px';
                } else {
                    currentDescEl.textContent = desc;
                    currentDescEl.style.padding = '6px 10px';
                    currentDescEl.style.color = 'inherit';
                    currentDescEl.style.fontStyle = 'normal';
                }
            } else {
                alert('保存失败，请重试');
            }
        });

        // 取消按钮点击事件
        cancelBtn.addEventListener('click', function() {
            const editor = descEditor.querySelector('textarea');
            const currentContent = editor ? editor.value : '';
            const originalContent = nodeData.description || '';
            
            // 如果内容未修改，直接取消
            if (currentContent === originalContent) {
                descEl.style.display = 'inline-block';
                descEditor.style.display = 'none';
                editBtn.style.display = 'inline-block';
                saveBtn.style.display = 'none';
                cancelBtn.style.display = 'none';
                return;
            }
            
            // 内容有修改则显示确认框
            const confirmed = window.confirm(
                '确定要取消编辑吗？\n' +
                '所有未保存的更改将会丢失。\n\n' +
                '按"确定"取消编辑，按"取消"继续编辑。'
            );
            if (confirmed) {
                // 恢复原始内容
                descEl.style.display = 'inline-block';
                descEditor.style.display = 'none';
                editBtn.style.display = 'inline-block';
                saveBtn.style.display = 'none';
                cancelBtn.style.display = 'none';
                
                // 恢复原始描述显示
                if (!originalDesc) {
                    descEl.textContent = '点击"编辑"添加描述';
                    descEl.style.color = '#666';
                    descEl.style.fontStyle = 'italic';
                } else if (descType === 'markdown') {
                    if (window.marked) {
                        try {
                            descEl.innerHTML = marked.parse(originalDesc);
                            descEl.style.padding = '6px 10px';
                            descEl.style.background = '#f8f8fa';
                            descEl.style.borderRadius = '6px';
                        } catch (e) {
                            descEl.textContent = originalDesc + ' (渲染错误)';
                        }
                    } else {
                        descEl.textContent = originalDesc + ' (请加载marked.js)';
                    }
                } else if (descType === 'html') {
                    descEl.innerHTML = originalDesc;
                    descEl.style.padding = '6px 10px';
                    descEl.style.background = '#f8f8fa';
                    descEl.style.borderRadius = '6px';
                } else {
                    descEl.textContent = originalDesc;
                    descEl.style.padding = '6px 10px';
                    descEl.style.color = 'inherit';
                    descEl.style.fontStyle = 'normal';
                }
            }
        });
        // 调试信息
        const desc = nodeData.description || '';
        console.group('Description Preview Debug');
        console.log('Description element exists:', !!descEl);
        console.log('Description content:', desc);
        console.log('Description type:', descType);
        console.log('Marked.js available:', !!window.marked);
        console.groupEnd();
        // 改进默认内容显示
        if (!desc) {
            descEl.textContent = '点击"编辑"添加描述';
            descEl.style.color = '#666';
            descEl.style.fontStyle = 'italic';
        } else if (descType === 'markdown') {
            if (window.marked) {
                try {
                    descEl.innerHTML = marked.parse(desc);
                    descEl.style.padding = '6px 10px';
                    descEl.style.background = '#f8f8fa';
                    descEl.style.borderRadius = '6px';
                } catch (e) {
                    console.error('Markdown渲染失败:', e);
                    descEl.textContent = desc + ' (渲染错误)';
                }
            } else {
                descEl.textContent = desc + ' (请加载marked.js)';
            }
        } else if (descType === 'html') {
            descEl.innerHTML = desc || '<i style="color:#666">点击"编辑"添加描述</i>';
            descEl.style.padding = '6px 10px';
            descEl.style.background = '#f8f8fa';
            descEl.style.borderRadius = '6px';
        } else {
            descEl.textContent = desc || '点击"编辑"添加描述';
            descEl.style.padding = '6px 10px';
            descEl.style.color = desc ? 'inherit' : '#666';
            descEl.style.fontStyle = desc ? 'normal' : 'italic';
        }
    }, 0);
    // 阻止弹窗区域点击冒泡，避免误关闭
    popupDiv.addEventListener('mousedown', e => e.stopPropagation());
    popupDiv.addEventListener('click', e => e.stopPropagation());
    // 阻止弹窗内滚轮事件冒泡，避免SVG整体缩放
    popupDiv.addEventListener('wheel', function(e) {
        e.stopPropagation();
    }, { passive: false });
    // 关闭按钮事件
    // 注册节点弹窗信息
    nodePopupRegistry.set(nodeData.id, {
        popupElement: popupDiv,
        nodeData: nodeData,
        position: { x: popupLeft, y: popupTop },
        lastPosition: { x: popupLeft, y: popupTop },
        lastSize: { width: '360px', height: '400px' },
        maximized: false,
        createdAt: new Date().toISOString(),
    });

    const closeBtn = popupDiv.querySelector('.node-details-close-btn');
    if (closeBtn) {
        closeBtn.addEventListener('mousedown', e => e.stopPropagation());
        closeBtn.addEventListener('click', function(e) {
            e.preventDefault();
            e.stopPropagation();
            popupDiv.remove();
            // 只移除当前弹窗对应的连线
            d3.select('svg').selectAll(`.node-details-curve[data-node-id="${nodeData.id}"]`).remove();
            // 从节点弹窗注册表中移除
            nodePopupRegistry.delete(nodeData.id);
        });
    }
    // 最大化/恢复按钮功能
    const maximizeBtn = popupDiv.querySelector('.node-details-maximize-btn');
    maximizeBtn.addEventListener('click', function() {
        const popupInfo = nodePopupRegistry.get(nodeData.id);
        
        if (!popupInfo.maximized) {
            // 保存当前状态到lastPosition/lastSize
            popupInfo.lastPosition = { 
                x: parseInt(popupDiv.style.left), 
                y: parseInt(popupDiv.style.top) 
            };
            popupInfo.lastSize = { 
                width: popupDiv.style.width,
                height: popupDiv.style.height
            };
            
            // 最大化
            popupDiv.style.left = '0';
            popupDiv.style.top = '0';
            popupDiv.style.width = '100%';
            popupDiv.style.height = '100%';
            popupDiv.style.borderRadius = '0';
            popupDiv.style.resize = 'none';
            
            // 更新图标和状态
            maximizeBtn.querySelector('.node-details-maximize-icon').textContent = '⧉';
            popupInfo.maximized = true;
        } else {
            // 恢复到上次位置和尺寸
            popupDiv.style.left = popupInfo.lastPosition.x + 'px';
            popupDiv.style.top = popupInfo.lastPosition.y + 'px';
            popupDiv.style.width = popupInfo.lastSize.width;
            popupDiv.style.height = popupInfo.lastSize.height;
            popupDiv.style.borderRadius = '8px';
            popupDiv.style.resize = 'both';
            
            // 更新图标和状态
            maximizeBtn.querySelector('.node-details-maximize-icon').textContent = '□';
            popupInfo.maximized = false;
        }
        
        if (window.simulation) window.simulation.alpha(0.3).restart();
    });

    // 边框拖动缩放功能
    enableResize(popupDiv, () => {
        // 更新最后尺寸
        const popupInfo = nodePopupRegistry.get(nodeData.id);
        popupInfo.lastSize = {
            width: popupDiv.style.width,
            height: popupDiv.style.height
        };
        // 更新连线
        drawPopupNodeCurve(popupDiv, nodeData);
        if (window.simulation) window.simulation.alpha(0.3).restart();
    });
    
    // 初始绘制连线
    drawPopupNodeCurve(popupDiv, nodeData);

    // 拖动逻辑 - 使用新的固定顶部栏
    const header = popupDiv.querySelector('.node-details-header');
    let isDragging = false, startX = 0, startY = 0, origLeft = popupLeft, origTop = popupTop;
    header.addEventListener('mousedown', function(e) {
        // 只有当点击的不是按钮区域时才触发拖动
        if (!e.target.closest('.node-details-buttons')) {
            isDragging = true;
            startX = e.clientX;
            startY = e.clientY;
            document.body.style.cursor = 'move';
            e.preventDefault();
            e.stopPropagation();
            window.addEventListener('mousemove', dragMove, true);
            window.addEventListener('mouseup', dragEnd, true);
        }
    });
    function dragMove(e) {
        if (!isDragging) return;
        dragOffset.x = origLeft + (e.clientX - startX);
        dragOffset.y = origTop + (e.clientY - startY);
        popupDiv.style.left = dragOffset.x + 'px';
        popupDiv.style.top = dragOffset.y + 'px';
        // 实时更新连线
        drawPopupNodeCurve(popupDiv, nodeData);
    }
    function dragEnd(e) {
        if (isDragging) {
            origLeft = dragOffset.x;
            origTop = dragOffset.y;
            isDragging = false;
            document.body.style.cursor = '';
            window.removeEventListener('mousemove', dragMove, true);
            window.removeEventListener('mouseup', dragEnd, true);
            
            // 更新最后位置
            const popupInfo = nodePopupRegistry.get(nodeData.id);
            popupInfo.lastPosition = { x: origLeft, y: origTop };
            // 更新连线
            drawPopupNodeCurve(popupDiv, nodeData);
        }
    }
    // 自动同步弹窗位置与节点移动
    function syncPopupPosition() {
        if (isDragging) return; // 拖拽时不自动同步
        
        const svgRect = svgNode.getBoundingClientRect();
        let t = d3.zoomTransform(svgNode);
        let screenX = t.applyX(node.x);
        let screenY = t.applyY(node.y);
        popupDiv.style.left = (svgRect.left + screenX + 60) + 'px';
        popupDiv.style.top = (svgRect.top + screenY + (node.radius || 0) + 40 - 20) + 'px';
        origLeft = svgRect.left + screenX + 60;
        origTop = svgRect.top + screenY + (node.radius || 0) + 40 - 20;
        // 实时更新连线
        drawPopupNodeCurve(popupDiv, nodeData);
    }
    // 监听d3力导向图tick事件
    if (window.simulation) {
        window.simulation.on('tick.nodeDetailsPopup', () => {
            syncPopupPosition();
            // 实时重绘连线
            drawPopupNodeCurve(popupDiv, nodeData);
        });
    }
    // 弹窗关闭时移除tick监听
    popupDiv.addEventListener('remove', function() {
        if (window.simulation) window.simulation.on('tick.nodeDetailsPopup', null);
        // 只移除当前弹窗对应的连线
        const curve = d3.select(`.node-details-curve[data-node-id="${nodeData.id}"]`);
        if (!curve.empty()) {
            curve.remove();
        }
    });
}


const searchInput = d3.select('.search-box input');
searchInput
    .on('input', function() {
        const searchTerm = this.value.trim().toLowerCase();
        const nodeSelection = d3.selectAll('.node-group');
        nodeSelection.classed('highlight', false)
            .select('circle')
            .attr('fill', d => d.color);
        if (searchTerm) {
            const matched = nodeSelection.filter(d => {
                if (!d.name) return false;
                const nameLower = d.name.toLowerCase();
                if (nameLower.includes(searchTerm)) return true;
                const pyFirst = getPinyinFirstLetters(d.name);
                if (pyFirst.includes(searchTerm)) return true;
                return false;
            })
                .classed('highlight', true)
                .select('circle')
                .attr('fill', '#ff5722');

            // 自动平移视图到第一个匹配节点
            const first = nodeSelection.filter(function(d) {
                if (!d.name) return false;
                const nameLower = d.name.toLowerCase();
                if (nameLower.includes(searchTerm)) return true;
                const pyFirst = getPinyinFirstLetters(d.name);
                if (pyFirst.includes(searchTerm)) return true;
                return false;
            }).data()[0];
            if (first) {
                const t = d3.zoomTransform(svg.node());
                const cx = first.x;
                const cy = first.y;
                const targetX = width / 2 - t.k * cx;
                const targetY = height / 2 - t.k * cy;
                svg.transition().duration(600)
                    .call(
                        d3.zoom().transform,
                        d3.zoomIdentity.translate(targetX, targetY).scale(t.k)
                    );
            }
        }
    })
    .on('keydown', function(event) {
        if (event.key === 'Enter') {
            const searchTerm = this.value.trim().toLowerCase();
            const nodeSelection = d3.selectAll('.node-group');
            // 获取所有匹配节点
            const matchedNodes = nodeSelection.filter(d => {
                if (!d.name) return false;
                const nameLower = d.name.toLowerCase();
                if (nameLower.includes(searchTerm)) return true;
                const pyFirst = getPinyinFirstLetters(d.name);
                if (pyFirst.includes(searchTerm)) return true;
                return false;
            }).data();
            // 隐藏输入框
            d3.select('.search-box').style('display', 'none');
            // 若有匹配节点
            if (matchedNodes.length > 0) {
                // 计算所有匹配节点的包围盒
                let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
                matchedNodes.forEach(n => {
                    minX = Math.min(minX, n.x - (n.radius || 0));
                    minY = Math.min(minY, n.y - (n.radius || 0));
                    maxX = Math.max(maxX, n.x + (n.radius || 0));
                    maxY = Math.max(maxY, n.y + (n.radius || 0));
                });
                // 计算重心
                const centerX = (minX + maxX) / 2;
                const centerY = (minY + maxY) / 2;
                // 计算缩放比例，使所有节点都能显示在视图内
                const bboxWidth = maxX - minX;
                const bboxHeight = maxY - minY;
                const margin = 60; // 额外留白
                const scale = Math.min(
                    width / (bboxWidth + margin),
                    height / (bboxHeight + margin),
                    2 // 最大放大倍数
                );
                // 计算平移，使重心居中
                const tx = width / 2 - scale * centerX;
                const ty = height / 2 - scale * centerY;
                // 先停止当前过渡，防止多次叠加
                svg.interrupt();
                // 通过d3-zoom的transform方法设置整体变换，确保g.nodes-container和g.links-container都被正确平移缩放
                // 立即刷新zoom监听器，确保动画立即生效
                const zoomBehavior = d3.zoom()
                    .scaleExtent([0.1, 10])
                    .on('zoom', (event) => {
                        svg.select('g.nodes-container').attr('transform', event.transform);
                        svg.select('g.links-container').attr('transform', event.transform);
                        // 在缩放时重绘所有弹窗连线
                        redrawLineOfPopupAndNode();
                    });
                svg.call(zoomBehavior);
                svg.transition().duration(700)
                    .call(zoomBehavior.transform, d3.zoomIdentity.translate(tx, ty).scale(scale));
            }
            // 清空输入
            this.value = '';
        }
    });



// 添加必要的CSS样式
    d3.select('head').append('style')
    .text(`
        .node-details-header:hover {
            background-color: rgba(0,0,0,0.1);
            box-shadow: inset 0 0 8px rgba(0,0,0,0.1);
        }
        .node-details-header:hover .node-details-dragbar {
            color: #4285f4;
            font-weight: bold;
        }
        .node-details-header:hover .node-details-buttons {
            background-color: transparent;
        }
        .node-details-close-btn:hover,
        .node-details-maximize-btn:hover {
            background-color: #f44336 !important;
            color: white !important;
        }
        .markdown-preview {
            max-height: 300px;
            overflow-y: auto;
            padding: 10px;
            background: #f8f9fa;
            border-radius: 6px;
            border: 1px solid #e1e4e8;
        }
        .markdown-preview pre {
            background-color: #f6f8fa;
            border-radius: 3px;
            padding: 16px;
            overflow: auto;
        }
        .markdown-preview code {
            font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;
            background-color: rgba(27,31,35,0.05);
            border-radius: 3px;
            padding: 0.2em 0.4em;
            font-size: 85%;
        }
        .node-form {
            width: 300px;
        }
        .pick-node-icon {
            transition: box-shadow 0.2s;
        }
        .pick-node-icon.dragging {
            box-shadow: 0 0 8px 2px #4285f4;
        }
        .node-form-container {
            z-index: 1000;
        }
        .highlight > circle {
            stroke: #ff9800 !important;
            stroke-width: 4 !important;
        }
        .node-details-popup {
            font-family: Arial, sans-serif;
            font-size: 14px;
            color: #333;
            background-color: rgba(255, 255, 255, 0.9);
            border-radius: 8px;
            padding: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
        }
        .node-details-title {
            margin: 0 0 10px 0;
            font-size: 16px;
            font-weight: bold;
            color: #4285f4;
        }
        .node-details-row {
            margin: 5px 0;
            line-height: 1.4;
        }
        .node-connections-list {
            margin: 10px 0 0 0;
            padding: 0;
            list-style-type: none;
        }
        .node-connections-list li {
            margin-bottom: 5px;
            padding-left: 10px;
            position: relative;
        }
        .node-connections-list li:before {
            content: '→';
            position: absolute;
            left: 0;
            top: 0;
            color: #4285f4;
        }
        .desc-type-select {
            padding: 4px 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            background-color: #fff;
            font-size: 13px;
        }
        .save-desc-btn {
            padding: 4px 12px;
            background-color: #4285f4;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 13px;
        }
        .save-desc-btn:hover {
            background-color: #3367d6;
        }
        /* 取消按钮样式 */
        .cancel-edit-btn {
            padding: 4px 12px;
            background-color: #f44336;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 13px;
            transition: background-color 0.2s;
        }
        .cancel-edit-btn:hover {
            background-color: #d32f2f;
            box-shadow: 0 1px 3px rgba(0,0,0,0.2);
        }
        .cancel-edit-btn:active {
            background-color: #b71c1c;
            transform: translateY(1px);
        }
    `);

import {createMainForm} from './forms/forms.js';
// 初始化节点表单
createMainForm();

// 响应窗口大小变化
window.addEventListener('resize', () => {
    const newWidth = window.innerWidth;
    const newHeight = window.innerHeight;
    svg.attr('width', newWidth).attr('height', newHeight);
    simulation.force('center', d3.forceCenter(newWidth / 2, newHeight / 2));
    simulation.force('x', d3.forceX(newWidth / 2).strength(0.05));
    simulation.force('y', d3.forceY(newHeight / 2).strength(0.05));
    simulation.alpha(0.3).restart();
});